package com.ljs.module.util;

import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.json.JSONObject;
import com.ljs.module.annotation.TemplateExtendKey;
import com.ljs.module.annotation.TemplateKey;
import com.ljs.module.common.DataBean;
import com.ljs.module.common.PathEnum;
import org.apache.commons.lang3.StringUtils;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TemplateUtil {
    public static final String JOINT_TEMPLATE_SPLIT = "#@!split!@#";
    //默认配置就够用了
    private static TemplateEngine engine = cn.hutool.extra.template.TemplateUtil.createEngine(new TemplateConfig(PathEnum.TEMPLATE.getPath(), TemplateConfig.ResourceMode.FILE));

    public static String render(String path, Map<String, Object> bindingMap) {
        return engine.getTemplate(path).render(bindingMap);
    }

    public static String renderString(String content, Map<String, Object> bindingMap) {
        TemplateEngine stringEngine = cn.hutool.extra.template.TemplateUtil.createEngine(new TemplateConfig());
        return stringEngine.getTemplate(content).render(bindingMap);
    }

    public static Map<String, Object> getTemplateKeyORM(Object... templateObj){
        Map<String, Object> map = new HashMap<>();

        for (Object o : templateObj) {
            map.putAll(getTemplateKeyORM(o));
        }
        return map;
    }

    public static <T> Map<String, Object> getTemplateKeyORM(T templateObj){
        if (templateObj == null) {
            return new HashMap<>();
        }
        Map<String, Object> map = new HashMap<>();
        Class<?> aClass = templateObj.getClass();

        List<Field> declaredFields = Util.getAllField(aClass);
        for (Field declaredField : declaredFields) {
            TemplateKey annotation = declaredField.getAnnotation(TemplateKey.class);
            if (annotation != null) {
                Type type = declaredField.getGenericType();
                if(type instanceof Class<?>) {
                    Class<?> cls = (Class<?>) type;
                    TemplateKey templateAnnotation = cls.getAnnotation(TemplateKey.class);
                    if (templateAnnotation != null) {
                        try {
                            declaredField.setAccessible(true);
                            map.putAll(TemplateUtil.getTemplateKeyORM(declaredField.get(templateObj)));
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                        continue;
                    }
                }
                String key = "";
                if (StringUtils.isBlank(annotation.value())) {
                    key = declaredField.getName();
                } else {
                    key = annotation.value();
                }
                declaredField.setAccessible(true);
                try {
                    Object o = declaredField.get(templateObj);
                    if (o != null) {
                        map.put(key, o);
                    }
                } catch (IllegalAccessException e) {
                    System.err.println("解析模板key时出错");
                }
                continue;
            }
            TemplateExtendKey extend = declaredField.getAnnotation(TemplateExtendKey.class);
            if (extend != null) {
                declaredField.setAccessible(true);
                try {
                    String extendJson = (String)declaredField.get(templateObj);
                    JSONObject jsonObject = new JSONObject(extendJson);
                    Map<String, Object> extendMap = jsonObject.toBean(Map.class);
                    map.putAll(extendMap);
                } catch (Exception e) {
                    System.err.println("解析扩展属性出错");
                }
            }
        }
        return map;
    }

    public static String getParams(List<String> paramPaths, String endWith) {
        boolean havaFirst = false;
        StringBuffer stringBuffer = new StringBuffer();
        for (String path : paramPaths) {
            String content = FileUtil.readFile2Content(PathEnum.TEMPLATE + File.separator + "custom" + File.separator + path + endWith);
            if (!StringUtils.isBlank(content)) {
                if (havaFirst) {
                    stringBuffer.append("|");
                    stringBuffer.append(content);
                } else {
                    stringBuffer.append(content);
                }
                havaFirst = true;
            }
        }
        return Arrays.stream(stringBuffer.toString().split("\\|")).collect(Collectors.toSet()).stream().collect(Collectors.joining("|"));
    }

    public static String removeJsCode(String content) {
        String[] split = content.split(TemplateUtil.JOINT_TEMPLATE_SPLIT);
        return split[0] + split[1];
    }

    public static String removeAnnotation(String content) {
        String[] split = content.split("(\r\n)|(\n)");
        StringBuffer stringBuffer = new StringBuffer();
        for (String tmp : split) {
            tmp = tmp.trim();
            String[] split2 = tmp.split("");
            tmp = "";
            // 去除注释
            for (String s : split2) {
                if (s.equals("#")) {
                    break;
                }
                tmp += s;
            }
            tmp = tmp.trim();
            if (StringUtils.isBlank(tmp)) {
                System.err.println("无代码");
                continue;
            }
            stringBuffer.append(tmp);
        }
        return stringBuffer.toString();
    }

    public static DataBean<Map<String, Object>> getJsMap(String js, Map<String, Object> map) {
        ScriptEngineManager sem=new ScriptEngineManager();
        ScriptEngine engine=sem.getEngineByName("javascript");
        //定义js函数
        try {
            engine.eval(js);
        } catch (ScriptException e) {
            return DataBean.fail().setDesc("\r\n\r\njs脚本解析出错，请检查语法问题\r\n" + e.getMessage());
        }
        try {
            Invocable jsInvoke =(Invocable)engine; //Invocable是ScriptEngine的一个接口，调用函数需要强转
            return DataBean.success((Map<String, Object>)jsInvoke.invokeFunction("main", new Object[]{map, new HashMap<>()})).setDesc("解析成功");
        } catch (NoSuchMethodException ex) {
            return DataBean.fail().setDesc("\r\n\r\njs脚本解析出错，请是否修改函数名 目前只能默认为main" + ex.getMessage());
        } catch (ScriptException e) {
            return DataBean.fail().setDesc("\r\n\r\njs脚本解析出错，请代码运行是否有错，请填写正确的示例进行运行" + e.getMessage());
        }
    }

    public static DataBean<String[]> getJointData(String path, boolean noAnnotation) {
        File file = new File(PathEnum.JOINT_TEMPLATE + File.separator + path);
        if (!file.exists()) {
            return DataBean.fail(null);
        }
        String content = FileUtil.readFile2Content(file.getAbsolutePath());
        if (StringUtils.isBlank(content)) {
            return DataBean.fail(null);
        }
        if (noAnnotation) {
            content = TemplateUtil.removeAnnotation(content);
        }
        return DataBean.success(content.split(TemplateUtil.JOINT_TEMPLATE_SPLIT + "\r\n"));
    }
}
